package top.archiesean.common.core.utils.tree;

import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author ArchieSean
 * @description 构造树形结构工具类
 * @date 2023-12-31 22:49
 */
@Slf4j
public class TreeUtil {
    private TreeUtil(){}

    /**
     * 树形结构构建方法
     *
     * @param list       需要构建的数据
     * @param root       根节点parentId的值
     * @param comparator 比较器，用于按照指定逻辑排序
     * @param <T>        泛型
     * @return list
     */
    public static <T extends TreeNode> List<T> build(List<T> list, Long root, Comparator<T> comparator) {
        if (!Optional.ofNullable(list).isPresent()) {
            log.info("构建树形结构的数据为空！");
            return new ArrayList<>();
        }
        Comparator<T> tComparator = comparator != null ? comparator : defaultCompare();
        List<T> ts = list.stream()
                .filter(x -> x.getParentId().equals(root))
                .peek(x -> {
                    List<T> tempList = childrenData(x, list, tComparator);
                    x.setChildren(!tempList.isEmpty() ? tempList : null);
                })
                .sorted(tComparator)
                .collect(Collectors.toList());
        if (ts.isEmpty()) {
            return list;
        }
        return ts;
    }

    /**
     * 设置子集数据
     *
     * @param <T> 泛型
     * @return list
     */
    public static <T extends TreeNode> List<T> childrenData(T item, List<T> list, Comparator<T> comparator) {
        return list.stream()
                .filter(x -> x.getParentId().equals(item.getId()))
                .peek(x -> {
                    List<T> tempList = childrenData(x, list, comparator);
                    x.setChildren(!tempList.isEmpty() ? tempList : null);
                })
                .sorted(comparator)
                .collect(Collectors.toList());
    }

    /**
     * 默认的比较器
     *
     * @return Comparator
     */
    private static <T extends TreeNode<T>> Comparator<T> defaultCompare() {
        return Comparator.comparing(TreeNode::getId);
    }
}
